﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Déplace un objet dans le plan x-y-z tridimensionnel. 
    /// </summary>
    public sealed class TranslateTransform3D10 : AffineTransform3D10
    {
        #region DependencyProperties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="OffsetX"/>.
        /// </summary>
        public static readonly DependencyProperty OffsetXProperty =
            DependencyProperty.Register("OffsetX", typeof(float), typeof(TranslateTransform3D10),
            new PropertyMetadata(new PropertyChangedCallback(OffsetX_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="OffsetY"/>.
        /// </summary>
        public static readonly DependencyProperty OffsetYProperty =
            DependencyProperty.Register("OffsetY", typeof(float), typeof(TranslateTransform3D10),
            new PropertyMetadata(new PropertyChangedCallback(OffsetY_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="OffsetZ"/>.
        /// </summary>
        public static readonly DependencyProperty OffsetZProperty =
            DependencyProperty.Register("OffsetZ", typeof(float), typeof(TranslateTransform3D10),
            new PropertyMetadata(new PropertyChangedCallback(OffsetZ_PropertyChanged)));
        #endregion

        #region DependencyProperties Callbacks
        private static void OffsetX_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            (sender as TranslateTransform3D10).OnOffsetXChanged(e);
        }

        private static void OffsetY_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            (sender as TranslateTransform3D10).OnOffsetYChanged(e);
        }

        private static void OffsetZ_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            (sender as TranslateTransform3D10).OnOffsetZChanged(e);
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="TranslateTransform3D10"/>
        /// </summary>
        public TranslateTransform3D10()
            : base()
        {
            ComputeValue();
        }
        
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="TranslateTransform3D10"/>, à l'aide de l'offset <see cref="SlimDX.Vector3"/> spécifié. 
        /// </summary>
        /// <param name="offset"><see cref="SlimDX.Vector3"/> de l'offset du modèle.</param>
        public TranslateTransform3D10(SlimDX.Vector3 offset)
            : this(offset.X, offset.Y, offset.Z)
        { }

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="TranslateTransform3D10"/> à l'aide de l'offset spécifié.
        /// </summary>
        /// <param name="offsetX">Double qui spécifie la valeur X du <see cref="SlimDX.Vector3"/> spécifiant l'offset de la translation.</param>
        /// <param name="offsetY">Double qui spécifie la valeur Y du <see cref="SlimDX.Vector3"/> spécifiant l'offset de la translation.</param>
        /// <param name="offsetZ">Double qui spécifie la valeur Z du <see cref="SlimDX.Vector3"/> spécifiant l'offset de la translation.</param>
        public TranslateTransform3D10(float offsetX, float offsetY, float offsetZ)
            : base()
        {
            this.OffsetX = offsetX;
            this.OffsetY = offsetY;
            this.OffsetZ = offsetZ;
        }
        #endregion

        #region Data
        private SlimDX.Matrix _value;
        #endregion

        #region Public Properties
        /// <summary>
        /// Obtient ou définit la valeur de l'axe X de l'offset de la translation. 
        /// </summary>
        public float OffsetX
        {
            get { return (float)GetValue(OffsetXProperty); }
            set { SetValue(OffsetXProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit la valeur de l'axe Y de l'offset de la translation. 
        /// </summary>
        public float OffsetY
        {
            get { return (float)GetValue(OffsetYProperty); }
            set { SetValue(OffsetYProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit la valeur de l'axe Z de l'offset de la translation. 
        /// </summary>
        public float OffsetZ
        {
            get { return (float)GetValue(OffsetZProperty); }
            set { SetValue(OffsetZProperty, value); }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Crée un clone modifiable de ce <see cref="TranslateTransform3D10"/>, en créant des copies complètes des valeurs de l'objet.
        /// Lors de la copie de propriétés de dépendance, cette méthode copie les références de ressources et les liaisons de données (même si elles ne peuvent plus être résolues), mais pas les animations ni leurs valeurs actuelles.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété IsFrozen de l'objet cloné est false, même si la valeur de la propriété IsFrozen de la source est true.
        /// </returns>
        public new TranslateTransform3D10 Clone()
        { 
            return base.Clone() as TranslateTransform3D10;
        }

        /// <summary>
        /// Crée un clone modifiable de cet objet <see cref="TranslateTransform3D10"/>, en créant des copies complètes des valeurs actuelles de cet objet.
        /// Contrairement à leurs valeurs actuelles, les références de ressources, les liaisons de données et les animations ne sont pas copiées.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété IsFrozen de l'objet cloné est false, même si la valeur de la propriété IsFrozen de la source est true.
        /// </returns>
        public new TranslateTransform3D10 CloneCurrentValue()
        {
            return base.Clone() as TranslateTransform3D10;
        }
        #endregion

        #region Private Methods
        private void OnOffsetXChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void OnOffsetYChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void OnOffsetZChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void ComputeValue()
        {
            _value = SlimDX.Matrix.Translation(OffsetX, OffsetY, OffsetZ);
        }
        #endregion

        #region Transform3D Implementation
        /// <summary>
        /// Obtient <see cref="SlimDX.Matrix"/> qui représente la valeur de la translation.
        /// </summary>
        public override SlimDX.Matrix Value
        {
            get { return _value; }
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new TranslateTransform();
        }
        #endregion
    }
}
